跳到主要内容

Golang 命令行程序之 cobra 包

cobra 项目地址

Cobra 是什么?

Cobra 既是一个用于创建强大的现代 CLI 应用程序的库,也是一个用于生成应用程序和命令文件的程序。

cobra 中的主要概念

cobra 中有个重要的概念,分别是 commands、arguments 和 flags。其中 commands 代表行为,arguments 就是命令行参数(或者称为位置参数),flags 代表对行为的改变(也就是我们常说的命令行选项)。执行命令行程序时的一般格式为:

APPNAME COMMAND ARG --FLAG

比如下面的例子

# server是 commands,port 是 flag
hugo server --port=1313

# clone 是 commands,URL 是 arguments,brae 是 flag
git clone URL --bare

快速使用

首先安装 cobra 库

go get -u github.com/spf13/cobra
go get -u github.com/spf13/viper

然后就可以用 cobra 程序生成应用程序框架了:

cobra init [name] --pkg-name [pkgname]
# example
# 创建在当前目录下面
cobra init stcobra --pkg-name alsritter.icu/stcobra

此时的程序并没有什么功能,执行它只会输出一些默认的提示信息:

A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

使用 cobra 程序生成命令代码

除了生成应用程序框架,还可以通过 cobra add 命令生成子命令的代码文件,比如下面的命令会添加两个子命令 image 和 container 相关的代码文件(当项目目录下):

go install github.com/spf13/cobra-cli@latest

使用

cobra-cli add image
cobra-cli add container

它就会被添加到项目里面了

image.png

这两条命令分别生成了 stcobra 程序中 image 和 container 子命令的代码,当然了,具体的功能还得靠我们自己实现。

为命令添加具体的功能

到目前为止,我们一共为 stcobra 程序添加了三个 Command,分别是 rootCmd(cobra init 命令默认生成)、imageCmd 和 containerCmd。

打开文件 root.go ,找到变量 rootCmd 的初始化过程并为之设置 Run 方法:

Run: func(cmd *cobra.Command, args []string) {
fmt.Println("执行了 root 命令")
},

再次执行,不带参数就是输出

执行了 root 命令

再为这个应用添加一个 version 命令

cobra-cli add version

添加参数配置

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of stcobra",
Long: `All software has versions. This is stcobra's`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("stcobra version is v1.0")
},
}

为 Command 添加选项(flags)

选项(flags)用来控制 Command 的具体行为。根据选项的作用范围,可以把选项分为两类:

  • persistent
  • local

对于 persistent 类型的选项,既可以设置给该 Command,又可以设置给该 Command 的子 Command。

示例:

对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:

var Verbose bool

func init() {
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
}

local 类型的选项只能设置给指定的 Command,比如下面定义的 source 选项(该选项不能指定给 rootCmd 之外的其它 Command):

var Source string

rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

默认情况下的选项都是可选的,但一些用例要求用户必须设置某些选项,这种情况 cobra 也是支持的,通过 Command 的 MarkFlagRequired 方法标记该选项即可:

var Name string

rootCmd.Flags().StringVarP(&Name, "name", "n", "", "user name (required)")
rootCmd.MarkFlagRequired("name")

命令行参数(arguments) 校验

cobra 默认提供了一些验证方法:

  • NoArgs - 如果存在任何位置参数,该命令将报错
  • ArbitraryArgs - 该命令会接受任何位置参数
  • OnlyValidArgs - 如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错
  • MinimumNArgs(int) - 至少要有 N 个位置参数,否则报错
  • MaximumNArgs(int) - 如果位置参数超过 N 个将报错
  • ExactArgs(int) - 必须有 N 个位置参数,否则报错
  • ExactValidArgs(int) 必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
  • RangeArgs(min, max) - 如果位置参数的个数不在区间 min 和 max 之中,报错

也可以自定义这个校验

var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires a color argument")
}
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}

比如要让 Command cmdTimes 至少有一个位置参数,可以这样初始化它:

var cmdTimes = &cobra.Command{
Use:
Short:
Long:
Args: cobra.MinimumNArgs(1),
Run:
}

执行的各个阶段

Command 执行的操作是通过 Command.Run 方法实现的,为了支持我们在 Run 方法执行的前后执行一些其它的操作,Command 还提供了额外的几个方法,它们的执行顺序如下:

var rootCmd = &cobra.Command{
Use: "stcobra",
Short: "sparkdev's cobra demo",
Long: "the demo show how to use cobra package",
// 子命令会继承这个函数
PersistentPreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
},
PreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("cobra demo program, with args: %v\n", args)
},
PostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
},
// 子命令会继承这个函数
PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
},
}

References

Golang : cobra 包简介 Cobra README.md